package com.shelpe.services.sinbadgateway.controller;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.shelpe.services.sinbadgateway.client.AlgorithmClient;
import com.shelpe.services.sinbadgateway.client.AlgorithmClient.UpdateResponse;
import com.shelpe.services.sinbadgateway.client.CampaignClient;
import com.shelpe.services.sinbadgateway.client.LexiconClient;
import com.shelpe.services.sinbadgateway.client.LexiconClient.AdgroupRecordDto;
import com.shelpe.services.sinbadgateway.client.SimbaProxyBaseDto;
import com.shelpe.services.sinbadgateway.client.SinbadClient;
import com.shelpe.services.sinbadgateway.client.SinbadClient.AdgroupResponse;
import com.shelpe.services.sinbadgateway.entity.jpa.Adgroup;
import com.shelpe.services.sinbadgateway.entity.jpa.DriveType;
import com.shelpe.services.sinbadgateway.entity.jpa.Product;
import com.shelpe.services.sinbadgateway.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbadgateway.repository.jpa.ProductRepository;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/sinbadgateway/users/{user_id}")
@Slf4j
public class AdgroupController {

	@Autowired
	private LexiconClient lexiconClient;
	@Autowired
	private SinbadClient sinbadClient;
	@Autowired
	private CampaignClient campaignClient;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private ProductRepository productRepository;
	@Autowired
	private AlgorithmClient algorithmClient;

	@RequestMapping(method = RequestMethod.POST, path = "/adgroups")
	@ResponseBody
	public AdgroupDto createAdgroup(@PathVariable("user_id") long userID, @RequestBody AdgroupDto dto) {

		Assert.isTrue(dto.getProductID() > 0, "invalid_product_ID");
		Assert.isTrue(dto.getCampaignID() > 0, "invalid_campaign_ID");
		log.debug("createAdgroup: {}", dto);
		Product product = this.productRepository.findOne(dto.getProductID());
		Assert.notNull(product, "product_not_found");

		SinbadClient.AdgroupDto adgroup = new SinbadClient.AdgroupDto();
		BeanUtils.copyProperties(dto, adgroup);
		adgroup.setUserID(userID);
		if (StringUtils.isBlank(dto.getProductName())) {
			adgroup.setProductName((product.getProductName() != null && product.getProductName().length() > 20)
					? product.getProductName().substring(0, 20) : product.getProductName());
			dto.setProductName(adgroup.getProductName());
		}
		if (StringUtils.isBlank(dto.getProductUrl())) {
			adgroup.setProductUrl(product.getPictureUrl());
			dto.setProductUrl(adgroup.getProductUrl());
		}
		if (product.getItemImgs() != null) {
			if (StringUtils.isBlank(dto.getCreativeName())) {
				adgroup.setCreativeName((product.getProductName() != null && product.getProductName().length() > 20)
						? product.getProductName().substring(product.getProductName().length() - 20,
								product.getProductName().length())
						: product.getProductName());
				dto.setCreativeName(adgroup.getCreativeName());
			}

			if (StringUtils.isBlank(dto.getCreativeImgUrl())) {
				adgroup.setCreativeImgUrl(product.getItemImgs().iterator().next());
				dto.setCreativeImgUrl(adgroup.getCreativeImgUrl());
			}
		}

		adgroup.setDefaultPrice(5);
		adgroup.setDriveType(0);
		dto.setDriveType(adgroup.getDriveType());
		adgroup.setStatus(0);
		SinbadClient.AdgroupDto res = this.sinbadClient.createAdgroup(adgroup);
		log.debug("create adgroup: {}", res);

		if (res != null && res.getAdgroupID() > 0) {
			dto.setAdgroupID(res.getAdgroupID());
			// if (dto.getBudget() >= 30) {
			CampaignClient.CampaignDto campaignDto = new CampaignClient.CampaignDto();
			// campaignDto.setBudget(dto.getBudget());
			campaignDto.setUserID(userID);
			campaignDto = this.campaignClient.updateCampaign(dto.getCampaignID(), campaignDto);
			log.debug("update campaign budget: {} {}", res, campaignDto);
			// }

			// 同步推荐词和大盘数据
			log.debug("sync ————————recommends:—————— {}", dto);
			this.synData(dto.getAdgroupID());
		} else {
			if (res.getError() != null) {
				log.error("fail to create creatives as sync: {} ", "(原因为" + res.getError().getSubMessage() + ")");
				dto.setError(res.getError());
			}
			log.error("fail to create adgroup: {},res:{}", dto, res);
		}
		return dto;
	}

	// 推荐词
	public void synData(final long adgroupID) {
		LexiconClient.Response lexiconRes = this.lexiconClient.createAdgroupRecord(adgroupID,
				new AdgroupRecordDto(true));
		log.debug("sync recommends completed: {} ", lexiconRes);
		if (!lexiconRes.isStatus()) {
			if (lexiconRes.getError() != null) {
				log.error("fail to sync recommend as sync: {} ",
						"(同步推荐词原因为" + lexiconRes.getError().getSubMessage() + ")");
			}
		} else {
			// 大盘数据
			LexiconClient.AdgroupMetricDto dtos = new LexiconClient.AdgroupMetricDto();
			LexiconClient.Response res = lexiconClient.syncAdgroupRecordMetrics(adgroupID, dtos);
			log.debug("sync insight completed: {}", res);
			if (res != null && res.getError() != null) {
				log.error("fail to sync recommend metric as sync: {} ",
						"(同步推荐词原因为" + lexiconRes.getError().getSubMessage() + ")");
			}
		}
	}

	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/@manualsync")
	@ResponseBody
	public Response ManualsyncAdgroup(@PathVariable("adgroup_id") long adgroupID) {
		this.synData(adgroupID);
		Response res = new Response();
		res.setStatus(true);
		return res;
	}

	@Data
	public static class AdgroupDto {

		@JsonProperty("adgroup_id")
		private long adgroupID;

		@JsonProperty("campaign_id")
		private long campaignID;
		@JsonProperty("product_id")
		private long productID;
		@JsonProperty("img_url")
		private String productUrl;
		@JsonProperty("default_price")
		private int defaultPrice;
		// private int budget;
		@JsonProperty("title")
		private String productName;
		@JsonProperty("drive_type")
		private int driveType = -1;

		@JsonProperty("creative_title")
		private String creativeName;
		@JsonProperty("creative_img_url")
		private String creativeImgUrl;

		private int limit;

		private SimbaProxyBaseDto.Error error;
	}

	@RequestMapping(method = RequestMethod.POST, path = "/camgroups")
	@ResponseBody
	public CampaignAdgroupDto createAdgroupWithCampaign(@PathVariable("user_id") long userID,
			@RequestBody CampaignAdgroupDto dto) {
		Assert.isTrue(dto.getBudget() >= 30 || dto.getBudget() == 0, "budget_less_than_30");
		Assert.isTrue(dto.getDefaultPrice() > 5, "default_price_less_than_5");

		Product product = this.productRepository.findOne(dto.getProductID());
		Assert.notNull(product, "product_not_found");

		CampaignClient.CampaignDto campaignDto = new CampaignClient.CampaignDto();
		campaignDto.setBudget(dto.getBudget());
		campaignDto.setTitle(dto.getTitle());
		campaignDto.setAutoType(2);
		campaignDto = this.campaignClient.createCampaign(campaignDto);
		Assert.notNull(campaignDto, "create_campaign_failure");
		Assert.isTrue(campaignDto.getCampaignID() > 0, "create_campaign_failure");
		log.debug("create campaign {} successfully", campaignDto.getCampaignID());

		SinbadClient.AdgroupDto adgroup = new SinbadClient.AdgroupDto();
		BeanUtils.copyProperties(dto, adgroup);
		adgroup.setUserID(userID);
		adgroup.setCampaignID(campaignDto.getCampaignID());
		if (StringUtils.isBlank(dto.getProductName())) {
			adgroup.setProductName((product.getProductName() != null && product.getProductName().length() > 20)
					? product.getProductName().substring(0, 20) : product.getProductName());
		}
		if (StringUtils.isBlank(dto.getProductUrl())) {
			adgroup.setProductUrl(product.getPictureUrl());
		}
		adgroup.setDriveType(0);
		adgroup.setStatus(0);
		SinbadClient.AdgroupDto res = this.sinbadClient.createAdgroup(adgroup);
		Assert.notNull(res, "create_adgroup_failure");
		Assert.isTrue(res.getAdgroupID() > 0, "create_adgroup_failure");
		dto.setAdgroupID(res.getAdgroupID());
		log.debug("create adgroup {} successfully", dto.getAdgroupID());

		this.synData(dto.getAdgroupID());

		return dto;
	}

	@Data
	@JsonInclude(Include.NON_NULL)
	public static class CampaignAdgroupDto {

		@JsonProperty("adgroup_id")
		private long adgroupID;
		@JsonProperty("campaign_id")
		private long campaignID;

		@JsonProperty("product_id")
		private long productID;
		@JsonProperty("default_price")
		private int defaultPrice;
		@JsonProperty("adgroup_title")
		private String productName;
		@JsonProperty("img_url")
		private String productUrl;

		@JsonProperty("campaign_title")
		private String title;
		private int budget;

	}

	@Data
	public static class Response {
		private boolean status;
	}

	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/@sync")
	@ResponseBody
	public Response createAdgroup(@PathVariable("adgroup_id") long adgroupID) {
		this.synData(adgroupID);
		Response res = new Response();
		res.setStatus(true);
		return res;
	}

	@RequestMapping(method = RequestMethod.PUT, path = "/adgroups/{adgroup_id}")
	@ResponseBody
	public AdgroupDto updateAdgroup(@PathVariable("adgroup_id") long adgroupID, @RequestBody AdgroupDto dto) {
		log.debug("*****start wireupdateAdgroup******:", dto);
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_foud");
		log.debug("updateAdgroup: {}, {}", adgroupID, dto);
		SinbadClient.AdgroupDto adgroupDto = new SinbadClient.AdgroupDto();
		BeanUtils.copyProperties(adgroup, dto);
		dto.setAdgroupID(adgroup.getAutoID());
		SinbadClient.AdgroupDto resDto = this.sinbadClient.updateAdgroup(adgroupID, adgroupDto);
		if (resDto != null && resDto.getAdgroupID() > 0) {
			dto.setAdgroupID(resDto.getAdgroupID());
			if (adgroup.getDriveType().getValue() == 2 && dto.getDriveType() == 0) {
				adgroup.setDriveType(DriveType.from(dto.getDriveType()));
				UpdateResponse res = this.algorithmClient.stopPlans(adgroupID);
				log.debug("stopPlans: {}", res);
			}
		}
		BeanUtils.copyProperties(dto, adgroupDto);
		return dto;
	}

	@RequestMapping(path = "/adgroups/{adgroup_id}/@autosyncLimit", method = RequestMethod.GET)
	@ResponseBody
	public KeywordResponse updateKeywordWithDevelopments(@PathVariable("adgroup_id") long adgroupID) {
		KeywordResponse res = new KeywordResponse();
		UpdateResponse updateRes = this.algorithmClient.syncPlans(adgroupID);
		AdgroupResponse adgroupRes = this.sinbadClient.updateAdgroupWithKeyword(adgroupID);
		log.debug("keyword:{} developments:{}", adgroupRes, updateRes);

		res.setStatus(true);
		return res;
	}

	@RequestMapping(path = "/campaigns/{campaign_id}/@autoSyncPrice", method = RequestMethod.PUT)
	@ResponseBody
	public AdgroupDto updateCampaignWithKeywordPrice(@PathVariable("campaign_id") long campaignID,
			@RequestBody AdgroupDto dto) {
		List<Adgroup> adgroups = this.adgroupRepository.findByCampaignID(campaignID);
		for (Adgroup adgroup : adgroups) {
			if (adgroup.getDriveType() != DriveType.manual && adgroup.getLimit() != dto.getLimit()) {
				SinbadClient.AdgroupDto adgroupDto = new SinbadClient.AdgroupDto();
				adgroupDto.setAdgroupID(adgroup.getAutoID());
				adgroupDto.setLimit(dto.getLimit());
				SinbadClient.AdgroupDto resDto = this.sinbadClient.updateAdgroup(adgroup.getAutoID(), adgroupDto);
				log.debug("before adgroup:{}>>>>after adgroupDto:{}", adgroup, resDto);
				BeanUtils.copyProperties(resDto, dto);
				if (resDto.getLimit() != adgroup.getLimit()) {
					AdgroupResponse adgroupRes = this.sinbadClient.updateAdgroupWithKeyword(adgroup.getAutoID());
					log.debug("keywords:{}", adgroupRes);
				}
			}

		}
		log.debug("finish update campaignPrice:{},{}", dto, adgroups);
		return dto;
	}

	@Data
	public static class KeywordResponse {
		private boolean status;
	}
}
